﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vibz.TeamAssignment.Common.Entity;
using System.Xml.Linq;
using Vibz.SharePoint;
using Vibz.SharePoint.Query;

namespace Vibz.TeamAssignment.Sharepoint
{
    public class SPList
    {
        public SPList(SPWeb web, SPSiteData siteData)
        {
            Console.WriteLine(DateTime.Now.ToLongTimeString() + "\tSPList Constructor");
            // SPListCache.Clear();
            Web = web;
            SiteData = siteData;
        }
        public static SPWeb Web
        {
            get;
            set;
        }
        public static SPSiteData SiteData
        {
            get;
            set;
        }
        internal List<string> AssignStatusList
        {
            get
            {
                return SPListCache.GetList<string>("AssignStatus", GetAssignStatus, null, 6 * QueryInterval);
            }
        }
        internal List<Task> ActiveTasks
        {
            get
            {
                return SPListCache.GetList<Task>("ActiveTasks", GetTask, Expression.Create(
                        Expression.Create("TaskStatus", "Active", Operator.Eq),
                        Expression.Create("TaskStatus", "Open", Operator.Eq),
                        Operand.Or), QueryInterval);
            }
        }
        internal List<TaskAssignment> ActiveAssignments
        {
            get
            {
                int[] activeTaskIds = ActiveTasks.Select(task => task.TaskID).ToArray();

                return SPListCache.GetList<TaskAssignment>("ActiveAssignments", GetTaskAssignment,
                    Expression.Create<int>("TaskID", activeTaskIds), QueryInterval);
            }
        }
        internal List<TaskGroupOwner> TaskGroupOwner
        {
            get
            {
                return SPListCache.GetList<TaskGroupOwner>("TaskGroupOwner", GetTaskGroupOwner, null, 2 * QueryInterval);
            }
        }
        internal List<TaskGroup> TaskGroup
        {
            get
            {
                return SPListCache.GetList<TaskGroup>("TaskGroup", GetTaskGroup, null, 6 * QueryInterval);
            }
        }
        internal List<Task> Task
        {
            get
            {
                return SPListCache.GetList<Task>("Task", GetTask, null, 60);
            }
        }
        internal List<TaskAssignment> TaskAssignment
        {
            get
            {
                return SPListCache.GetList<TaskAssignment>("TaskAssignment", GetTaskAssignment, null, 10);
            }
        }
        internal List<TeamMember> TeamMember
        {
            get
            {
                return SPListCache.GetList<TeamMember>("TeamMember", GetTeamMember, null, 3600);
            }
        }
        internal List<TaskMasterEntry> TaskMaster
        {
            get
            {
                return SPListCache.GetList<TaskMasterEntry>("TaskMaster", GetTaskMaster, null, 3600);
            }
        }

        internal List<TaskGroupOwner> GetTaskGroupOwner(Expression exp)
        {
            return Web.GetListRecords<TaskGroupOwner>("TaskGroupOwner",
                new string[] { "GroupId", "OwnerId" },
                exp,
                delegate(XElement element)
                {
                    return new TaskGroupOwner(
                        GetElementValue<int>(element, "GroupId"),
                        GetElementValue<String>(element, "OwnerId"));
                });
        }
        internal List<TaskGroup> GetTaskGroup(Expression exp)
        {
            return Web.GetListRecords<TaskGroup>("TaskGroup", 
                new string[] { "ID", "Title" },
                exp,
                delegate(XElement element)
                {
                    return new TaskGroup(
                        GetElementValue<int>(element, "ID"),
                        GetElementValue<String>(element, "Title"));
                });
        }
        internal List<string> GetAssignStatus(Expression exp)
        {
            return Web.GetListColumnChoiceOptions("TaskAssignment", "AssignStatus");
        }
        internal Task GetTask(int taskID)
        {
            return SPListCache.GetItem<Task>("Task#" + taskID.ToString(), FetchTask, taskID, 60);
        }
        internal Task GetTask(string taskName)
        {
            return SPListCache.GetItem<Task>("Task#" + taskName, FetchTask, taskName, 60);
        }
        internal Task FetchTask(int taskID)
        {
            if(taskID == -1)
                return null;
            List<Task> taskList = GetTask(
                 Expression.Create("ID", taskID.ToString(), Operator.Eq), false
                );

            return (taskList.Count > 0) ? taskList[0] : null;
        }
        internal Task FetchTask(string taskName)
        {
            if(String.IsNullOrEmpty(taskName))
                return null;
            List<Task> taskList = GetTask(
                 Expression.Create("Title", taskName, Operator.Eq), false
                );

            return (taskList.Count > 0) ? taskList[0] : null;
        }
        internal List<Task> GetTask(Expression exp)
        {
            return GetTask(exp, true);
        }
        internal List<Task> GetTask(Expression exp, bool addInCache)
        {
            List<Task> retValue = Web.GetListRecords<Task>("Task",
                    new string[] { "Title", "ParentID", "ID", 
                        "TaskDescription", "DueDate", "EstimatedDuration", 
                        "ActualDuration", "GroupId", "CreatedBy", "GroupId", "TaskStatus" },
                        exp,
                delegate(XElement element)
                {
                    return new Task(
                        GetElementValue<int>(element, "ParentID"),
                        GetElementValue<String>(element, "Title"),
                        GetElementValue<String>(element, "TaskDescription"),
                        GetElementValue<DateTime>(element, "DueDate"),
                        GetElementValue<double>(element, "EstimatedDuration"),
                        GetElementValue<int>(element, "GroupId"),
                        GetElementValue<int>(element, "ID"),
                        GetElementValue<TaskStatus>(element, "TaskStatus"),
                        GetElementValue<double>(element, "ActualDuration"),
                        GetElementValue<String>(element, "CreatedBy")
                        );
                });
            if(addInCache)
                foreach(Task tsk in retValue)
                    SPListCache.AddItem<Task>("Task#" + tsk.TaskID.ToString(), tsk, 60);
            return retValue;
        }
        internal TaskAssignment GetLatestAssignment(int taskID)
        {
            return SPListCache.GetItem<TaskAssignment>("Assign#" + taskID.ToString(), FetchLatestAssignment, taskID, 60);
        }
        internal TaskAssignment FetchLatestAssignment(int taskID)
        {
            List<TaskAssignment> tAssList = GetTaskAssignment(
                 Expression.Create("TaskID", taskID.ToString(), Operator.Eq), false
                );

            List<TaskAssignment> tAssignments = (tAssList.Count > 0) ? tAssList
                    .Where(tAss => tAss.AssignStatus != AssignStatus.Rejected &&
                        tAss.AssignRequestDate == tAssList
                                .Where(tAss3 => tAss3.AssignStatus != AssignStatus.Rejected)
                                .Select(tAss2 => tAss2.AssignRequestDate)
                                .Max())
                    .ToList() : null;

            if(tAssignments == null || tAssignments.Count == 0)
                return null;
            return tAssignments[0];
        }
        internal List<TaskAssignment> GetAllAssignments(int taskID)
        {
            return GetTaskAssignment(
                 Expression.Create("TaskID", taskID.ToString(), Operator.Eq)
                );
        }

        internal List<TaskAssignment> GetTaskAssignment(Expression exp)
        {
            return GetTaskAssignment(exp, true);
        }
        internal List<TaskAssignment> GetTaskAssignment(Expression exp, bool addInCache)
        {
            List<TaskAssignment> retValue = Web.GetListRecords<TaskAssignment>("TaskAssignment",
                    new string[] { "TaskID", "AssignedTo", "AssignBy", 
                        "IsRequest", "AssignRequestDate", "AssignComment","AssignStatus" },
                        exp,
                delegate(XElement element)
                {
                    return new TaskAssignment(
                        GetElementValue<int>(element, "TaskID"),
                        GetElementValue<String>(element, "AssignedTo"),
                        GetElementValue<String>(element, "AssignBy"),
                        GetElementValue<bool>(element, "IsRequest"),
                        GetElementValue<DateTime>(element, "AssignRequestDate"),
                        GetElementValue<String>(element, "AssignComment"),
                        GetElementValue<AssignStatus>(element, "AssignStatus"),
                        GetElementValue<int>(element, "ID")
                        );
                });
            if(addInCache)
                foreach(TaskAssignment ass in retValue)
                    SPListCache.AddItem<TaskAssignment>("Assign#" + ass.TaskID.ToString(), ass, 30);
            return retValue;
        }
        internal List<TeamMember> GetTeamMember(Expression exp)
        {
            return Web.GetListRecords<TeamMember>("TeamMember",
                    new string[] { "ManagerID", "MemberID" },
                        exp,
                delegate(XElement element)
                {
                    return new TeamMember(
                        GetElementValue<String>(element, "MemberID"),
                        GetElementValue<String>(element, "ManagerID")
                        );
                });
        }
        internal List<TaskMasterEntry> GetTaskMaster(Expression exp)
        {
            return Web.GetListRecords<TaskMasterEntry>("TaskMaster",
                new string[] { "Key", "Value" },
                exp,
                delegate(XElement element)
                {
                    return new TaskMasterEntry(
                        GetElementValue<String>(element, "Key"),
                        GetElementValue<String>(element, "Value"));
                });
        }


        internal T GetElementValue<T>(XElement element, string columnName)
        {
            if(element.Attribute("ows_" + columnName) == null)
            {
                if(typeof(T) == typeof(DateTime))
                    return (T)Convert.ChangeType(DateTime.MinValue, typeof(T));
                else if(typeof(T) == typeof(int))
                    return (T)Convert.ChangeType(-1, typeof(T));
                else if(typeof(T) == typeof(double))
                    return (T)Convert.ChangeType(-1.0, typeof(T));
                else if(typeof(T) == typeof(bool))
                    return (T)Convert.ChangeType(false, typeof(T));
                else if(typeof(T).IsEnum)
                    return (T)Enum.GetValues(typeof(T)).GetValue(0);
                else
                    return (T)Convert.ChangeType("", typeof(T));
            }
            else
            {
                if(typeof(T) == typeof(DateTime))
                    return (T)Convert.ChangeType(((DateTime)element.Attribute("ows_" + columnName)).ToLocalTime(),
                        typeof(T));
                else if(typeof(T) == typeof(int) || typeof(T) == typeof(double))
                    return (T)Convert.ChangeType(double.Parse(element.Attribute("ows_" + columnName).Value), typeof(T));
                else if(typeof(T) == typeof(bool))
                    return (T)Convert.ChangeType(element.Attribute("ows_" + columnName).Value == "1", typeof(T));
                else if(typeof(T).IsEnum)
                {
                    string enumValue = element.Attribute("ows_" + columnName).Value;
                    if(enumValue.StartsWith(";#") && enumValue.EndsWith(";#"))
                        enumValue = enumValue.Replace(";#", "");
                    return (T)Enum.Parse(typeof(T), enumValue);
                }
                else
                    return (T)Convert.ChangeType(element.Attribute("ows_" + columnName).Value, typeof(T));
            }
        }

        public int QueryInterval
        {
            get
            {
                string uInterval = System.Configuration.ConfigurationManager.AppSettings["UpdateInterval"];
                int interval = 120;
                if(!String.IsNullOrEmpty(uInterval) && int.TryParse(uInterval, out interval))
                    ;
                return interval * 1000;
            }
        }
    }
}
